#ifndef _NE_SKELETON_H_
#define _NE_SKELETON_H_

#include <graphics/Joint.h>
#include <system/Resource.h>

namespace ne
{
    class NEAPI Skeleton : public Resource
    {
        public:
            Skeleton(ResourceManager *pManager,
                     const uint64_t id,
                     const std::string &name,
                     const std::string &fileName,
                     const bool isManual,
                     ManualResourceLoader *pLoader);

            virtual Joint* createJoint();
            
            virtual Joint* createJoint(const uint16_t handle);

            virtual Joint* createJoint(const std::string &name);

            virtual Joint* createJoint(const uint16_t handle, const std::string &name);

            virtual Joint* getJoint(const uint16_t handle) const;

            virtual Joint* getJoint(const std::string &name) const;

            virtual bool destroyJoint(Joint *joint);

            virtual bool destroyJoint(const uint16_t handle);

            virtual bool destroyJoint(const std::string &name);

            virtual void destroyAllJoint();

            virtual size_t getNumJoints() const;

            virtual bool hasJoint(const uint16_t handle) const;

            virtual bool hasJoint(const std::string &name) const;

            virtual bool isInternalJoint(const Joint *joint) const;

            virtual void setBinding();

            virtual void deriveRootJoint();

            virtual void reset(const bool resetManualJoints=false);

            virtual void update();

            virtual bool isManualJointsDirty() const;

            virtual bool hasManualJoints() const;

            virtual void getAllJointsOffsetTransformMatrices(Matrix4Vector &matrices);

            virtual const JointVector& getJointVector() const;

            virtual void copyFrom(const Skeleton &skeleton);

            virtual ~Skeleton();

            // Internal call function
            // Don't use it directly
            virtual bool _prepareRenameJoint(Joint *joint, const std::string &name);

            virtual void _notifyManualJointsDirty();

            virtual void _notifyManualJointChange(Joint *joint);

        protected:
            virtual bool loadImplement();

            virtual bool unloadImplement();

            virtual bool downloadImplement();

            virtual size_t _calculateSize() const;

            virtual void _update();

        public:
            static bool JointHandleLess(const Joint *jointA, const Joint *jointB);

        public:
            static const uint16_t MAX_JOINT_NUM_IN_ONE_SKELETON;

        protected:
            JointVector mJoints;
            JointHandleMap mJointHandleSearchMap;
            JointNameMap mJointNameSearchMap;
            mutable JointVector mRootJoints;
            JointSet mManualJoints;

            std::set<uint16_t> mAutoNextHandleSet;
            bool mManualJointsDirty;
    };

    class NEAPI SkeletonPtr : public SharedPtr<Skeleton>
    {
        public:
            SkeletonPtr() : SharedPtr<Skeleton>() {}
            explicit SkeletonPtr(Skeleton *pSkeleton) : SharedPtr<Skeleton>(pSkeleton) {}
            SkeletonPtr(const SkeletonPtr &pSkeleton) : SharedPtr<Skeleton>(pSkeleton) {}

            SkeletonPtr(const ResourcePtr &p)
                : SharedPtr<Skeleton>()
            {
                mpPtr = static_cast<Skeleton*>(p.ptr());
                mpUseCount = p.getUseCountPtr();
                if (mpUseCount)
                {
                    ++(*mpUseCount);
                }
            }

            SkeletonPtr& operator = (const ResourcePtr &p)
            {
                if (mpPtr == static_cast<Skeleton*>(p.ptr()))
                {
                    return *this;
                }
                SkeletonPtr temp(p);
                swap(temp);
                return *this;
            }
    };
}

#endif
